using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace StupidSpaceThing
{
    class ShaderSystem
    {
        private static bool Initialized { get { return (device != null); } }
        private static GraphicsDevice device;
        private static Effect effect;
        public static TextureTools.AnimatedTexture animatedTexture;
        public enum Technique { Default = 0 };
        public enum ParametersPresets { NotSat, Menu, Game } ;
        private static ParametersPresets currentPreset = ParametersPresets.NotSat;
        public static Technique ActiveTechnique = Technique.Default;
        public static EffectParameter WorldParameter;
        public static EffectParameter ViewParameter;
        public static EffectParameter ProjectionParameter;
        public static EffectParameter CameraPositionParameter;
        public static EffectParameter ColorParameter;
        public static EffectParameter EdgeColorParameter;
        public static EffectParameter TopLightColorParameter;
        public static EffectParameter BottomLightColorParameter;
        public static EffectParameter FogStartParameter;
        public static EffectParameter FogEndParameter;
        public static EffectParameter FogColorParameter;
        public static EffectParameter TopLightDirectionParameter;
        public static EffectParameter BottomLightDirectionParameter;
        public static EffectParameter TextureParameter;
        private static void CheckInit()
        {
            if (!Initialized)
            {
                throw new Exception("Error ShaderSystem not initialized.");
            }
        }
        public static void Init(GraphicsDevice device, Effect effect)
        {
            if (Initialized)
            {
                Console.Error.WriteLine("Warning: ShaderSystem already initialized.");
                return;
            }
            ShaderSystem.device = device;
            ShaderSystem.effect = effect;
            animatedTexture = new TextureTools.MovingSpots(64, 64, 32);
            //Effect parameters
            WorldParameter = effect.Parameters["World"];
            ViewParameter = effect.Parameters["View"];
            ProjectionParameter = effect.Parameters["Projection"];            
            CameraPositionParameter = effect.Parameters["CameraPosition"];
            ColorParameter = effect.Parameters["Color"];
            EdgeColorParameter = effect.Parameters["EdgeColor"];
            TopLightColorParameter = effect.Parameters["TopLightColor"];
            BottomLightColorParameter = effect.Parameters["BottomLightColor"];
            FogStartParameter = effect.Parameters["FogStart"];
            FogEndParameter = effect.Parameters["FogEnd"];
            FogColorParameter = effect.Parameters["FogColor"];
            TopLightDirectionParameter = effect.Parameters["TopLightDirection"];
            BottomLightDirectionParameter = effect.Parameters["BottomLightDirection"];
            TextureParameter = effect.Parameters["Texture"];
            //Set default values
            ColorParameter.SetValue(Color.Gray.ToVector4());
            EdgeColorParameter.SetValue(new Vector4(0.3f, 0.2f, 0.3f, 1.0f));
            TopLightColorParameter.SetValue(Color.LightGray.ToVector4());
            BottomLightColorParameter.SetValue(new Vector4(0.4f, 0.2f, 0.4f, 1.0f));
            FogStartParameter.SetValue(100.0f);
            FogEndParameter.SetValue(140.0f);
            FogColorParameter.SetValue(Color.Black.ToVector4());
            TopLightDirectionParameter.SetValue(Vector3.Up);
            BottomLightDirectionParameter.SetValue(Vector3.Normalize((new Vector3(0, -1, -0.5f))));
            AnimateTexture();
        }
        public static void Draw(ModelMesh mesh)
        {
            CheckInit();            
            ModelMeshPart meshPart = mesh.MeshParts[0];
            device.Vertices[0].SetSource(mesh.VertexBuffer, meshPart.StreamOffset, meshPart.VertexStride);
            device.VertexDeclaration = meshPart.VertexDeclaration;
            device.Indices = mesh.IndexBuffer;
            effect.CurrentTechnique = effect.Techniques[(int)ActiveTechnique];
            effect.Begin(SaveStateMode.None);
            int passCount = effect.CurrentTechnique.Passes.Count;
            for (int i = 0; i < passCount; i++)
            {
                effect.CurrentTechnique.Passes[i].Begin();
                device.DrawIndexedPrimitives(PrimitiveType.TriangleList, meshPart.BaseVertex, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
                effect.CurrentTechnique.Passes[i].End();
            }
            effect.End();
        }
        public static void AnimateTexture()
        {
            animatedTexture.Update();
            TextureParameter.SetValue(animatedTexture.Texture);
        }
        public static void SetParametersFor(ParametersPresets preset)
        {
            if (preset == currentPreset)
            {
                return;
            }
            else
            {
                currentPreset = preset;
                switch (preset)
                {
                    case ParametersPresets.Menu:
                        TopLightDirectionParameter.SetValue(Vector3.Normalize((new Vector3(0, 1, 0.5f))));
                        BottomLightDirectionParameter.SetValue(Vector3.Normalize((new Vector3(0, -1, 0.5f))));
                        BottomLightColorParameter.SetValue(Color.DarkGoldenrod.ToVector4());
                        FogStartParameter.SetValue(140.0f);
                        FogEndParameter.SetValue(180.0f);
                        break;
                    case ParametersPresets.Game:
                        TopLightDirectionParameter.SetValue(Vector3.Up);
                        BottomLightDirectionParameter.SetValue(Vector3.Normalize((new Vector3(0, -1, -0.5f))));
                        TopLightColorParameter.SetValue(Color.LightGray.ToVector4());
                        BottomLightColorParameter.SetValue(new Vector4(0.4f, 0.2f, 0.4f, 1.0f));
                        FogStartParameter.SetValue(100.0f);
                        FogEndParameter.SetValue(140.0f);
                        break;
                    case ParametersPresets.NotSat:
                        // do nothing
                        break;
                    default:
                        throw new Exception("Unknow parameter preset");
                }
            }
        }
    }
}
